home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 5
/
Apprentice-Release5.iso
/
Source Code
/
Libraries
/
DCLAP 6d
/
dclap6d
/
corelib
/
ncbiprop.c
< prev
next >
Wrap
Text File
|
1996-07-05
|
17KB
|
638 lines
/* ncbiprop.h
* ===========================================================================
*
* PUBLIC DOMAIN NOTICE
* National Center for Biotechnology Information
*
* This software/database is a "United States Government Work" under the
* terms of the United States Copyright Act. It was written as part of
* the author's official duties as a United States Government employee and
* thus cannot be copyrighted. This software/database is freely available
* to the public for use. The National Library of Medicine and the U.S.
* Government have not placed any restriction on its use or reproduction.
*
* Although all reasonable efforts have been taken to ensure the accuracy
* and reliability of the software and data, the NLM and the U.S.
* Government do not and cannot warrant the performance or results that
* may be obtained by using this software or data. The NLM and the U.S.
* Government disclaim all warranties, express or implied, including
* warranties of performance, merchantability or fitness for any particular
* purpose.
*
* Please cite the author in any work or product based on this material.
*
* ===========================================================================
*
* File Name: ncbiprop.h
*
* Author: Schuler
*
* Version Creation Date: 06-04-93
*
* $Revision: 2.12 $
*
* File Description: Application Property Functions.
*
* Application properties were introduced to allow the NCBI Toolbox
* to be implemented as a dynamic link library (DLL). Under Windows,
* global variables located in the DLL are not instantiated for each
* application instance, but instead shared by all applications having
* a run-time linkage. Values that might ordinarily be stored in
* global variables can instead be saved as application properties
* (unless sharing is desired, of course). An application property
* is simply a pointer (or other value cast to a pointer) that is
* identified by a string key. Properties are kept in a linked list
* (sorted by key) whose head is stored in an application context block.
* The application context block is created on-demand and marked
* with the process ID of the calling application (or it's creation
* can be forced by calling InitAppContext() at the beginning of your
* program. The linked list of (smallish) application context
* structures is the only thing allocated from the DLL's data space,
* all other memory is owned by the application that called the DLL
* is automatically freed by the system when the application terminates.
*
* If this code is not actually compiled as a DLL, but bound at link
* time to a single application in the normal way, the behavior of all
* functions will be the same. The only difference being that the
* list of application context structures will contain exactly one item.
*
* Modifications:
* --------------------------------------------------------------------------
* Date Name Description of modification
* ------- ---------- -----------------------------------------------------
*
* ==========================================================================
*/
#include <ncbi.h>
#include <ncbiwin.h>
/* ----------------------------------------------------------------------
* new_AppProperty allocates/constructs an AppProperty struct
* delete_AppProperty deallocates/destructs an AppProperty struct
*
* Created:
* 06-04-93 Schuler
* Modified:
* 00-00-00 YourName What changes did you make?
* ---------------------------------------------------------------------- */
typedef struct _AppProperty_
{
struct _AppProperty_ *next;
char *key;
void *data;
}
AppProperty;
static AppProperty * new_AppProperty PROTO((const char *key, void *data));
static void delete_AppProperty PROTO((AppProperty *prop));
static AppProperty * new_AppProperty (const char *key, void *data)
{
AppProperty *prop = (AppProperty*) MemNew(sizeof(AppProperty));
ASSERT(key != NULL);
ASSERT(*key != '\0');
if (prop != NULL)
{
if ( ! (prop->key = StrSave(key)) )
prop = (AppProperty*) MemFree(prop);
else
prop->data = data;
}
return prop;
}
static void delete_AppProperty (AppProperty *prop)
{
ASSERT(prop != NULL);
MemFree(prop->key);
MemFree(prop);
}
/* ----------------------------------------------------------------------
* new_AppContext allocates/constructs an AppContext struct
* delete_AppContext deallocates/destructs an AppContext struct
*
* Notes: (1) If a valid context cannot be created, the application halts.
* (2) The memory allocated for the AppContext struct is owned by
* the DLL and the scratch buffer is owned by the application.
* (3) It is important that this function NOT call TRACE, Message,
* or ErrPost (or anything else that could result in any of these
* being called) as they use the applicaion context's scratch buffer.
*
* Created:
* 06-04-93 Schuler
* Modified:
* 00-00-00 YourName What changes did you make?
* ---------------------------------------------------------------------- */
#define SCRATCH_SIZE_DEFAULT (2*KBYTE)
typedef struct _AppContext_
{
struct _AppContext_ *next;
struct _AppProperty_ *proplist;
long pid;
unsigned enums :15; /* number of nested enumerations in-progress */
unsigned lock :1; /* if TRUE, property list is locked */
Nlm_sizeT scratch_size;
void *scratch;
}
AppContext;
/* this is the only global variable in this file: */
static AppContext * g_appList; /* Application Context List */
static AppContext * new_AppContext PROTO((long pid));
static void delete_AppContext PROTO((AppContext *prop));
INLINE static void AppContext_Lock PROTO((AppContext *context));
INLINE static void AppContext_Unlock PROTO((AppContext *context));
INLINE static unsigned AppContext_IsLocked PROTO((AppContext *context));
static AppContext * new_AppContext (long pid)
{
AppContext *context = (AppContext*) dll_Malloc(sizeof(AppContext));
if (context == NULL)
AbnormalExit(1);
memset((void*)context,0,sizeof(struct _AppContext_));
context->pid = pid;
context->scratch_size = SCRATCH_SIZE_DEFAULT;
context->scratch = Malloc(SCRATCH_SIZE_DEFAULT);
if (context->scratch == NULL)
AbnormalExit(1);
return context;
}
static void delete_AppContext (AppContext *context)
{
AppProperty *p1, *p2;
ASSERT(context != NULL);
for (p1=context->proplist; p1; p1=p2)
{
p2 = p1->next;
delete_AppProperty(p1);
}
Free(context->scratch);
dll_Free(context);
}
static INLINE void AppContext_Lock (AppContext *context)
{
ASSERT(context->lock==0);
context->lock = 1;
}
static INLINE void AppContext_Unlock (AppContext *context)
{
ASSERT(context->lock==1);
context->lock = 0;
}
static INLINE unsigned AppContext_IsLocked (AppContext *context)
{
return context->lock;
}
/* ----------------------------------------------------------------------
* InitAppContext -- Initializes a context struct for current application.
*
* Notes:
* If a valid context cannot be created, the application halts.
* Although it is not strictly necessary to call InitAppContext() as
* contexts are created on-demand, calling it once at the beginning
* of the program may reduce heap fragmentation.
*
* Created:
* 06-04-93 Schuler
* Modified:
* 00-00-00 YourName What changes did you make?
*
* ---------------------------------------------------------------------- */
/* helper functions for internal use only */
AppContext *GetAppContext PROTO((void));
char * GetScratchBuffer PROTO((void));
Nlm_sizeT GetScratchBufferSize PROTO((void));
void LIBCALL Nlm_InitAppContext ()
{
GetAppContext ();
}
AppContext *GetAppContext (void)
{
long pid = Nlm_GetAppProcessID();
AppContext *p1, *p2;
AppContext *app;
/*
* First we scan the list of contexts for one with the current
* application's process ID.
*/
for (p1=g_appList,p2=NULL; p1; p1=p1->next)
{
if (p1->pid == pid) return p1;
if (p1->pid > pid) break;
p2 = p1;
}
/*
* If we reach this point, the context for current does not
* exist yet, so we need to create one and link it into the list.
*/
app = new_AppContext(pid);
if (p2 == NULL)
g_appList = app;
else
p2->next = app;
app->next = p1;
return app;
}
char * GetScratchBuffer ()
{
return (char *) GetAppContext()->scratch;
}
Nlm_sizeT GetScratchBufferSize ()
{
return GetAppContext()->scratch_size;
}
/* ----------------------------------------------------------------------
* ReleaseAppContext -- frees application context struct for current app.
*
* Notes:
* For most platforms, memory will be recovered automatically by the
* operating system. However, since we cannot guarantee this for
* all systems, it might be wise to call ReleaseAppContext() once
* just before the application exits.
*
* Created:
* 06-04-93 Schuler
* Modified:
*
* ---------------------------------------------------------------------- */
void LIBCALL Nlm_ReleaseAppContext (void)
{
long pid = Nlm_GetAppProcessID();
AppContext *p1, *p2;
/*
* Scan the list for the context of the current app
*/
for (p1=g_appList,p2=NULL; p1; p1=p1->next)
{
if (p1->pid == pid) break;
p2 = p1;
}
/*
* Adjust links and release memory
*/
if (p1 != NULL)
{
if (p2 == NULL)
g_appList = p1->next;
else
p2->next = p1->next;
delete_AppContext(p1);
}
}
/* ----------------------------------------------------------------------
* SetAppProperty -- Sets a data item int the application context's
* property list, replacing the existing one or creating a new
* one if no property with that key exists.
*
* Parameters:
* key: key identifying the property
* value: pointer to arbitrary data
*
* Return value:
* Previous value of the property, if any, or NULL otherwise.
*
* Created:
* 06-08-93 Schuler
* Modified:
* 00-00-00 YourName What changes did you make?
* ---------------------------------------------------------------------- */
void * LIBCALL Nlm_SetAppProperty (const char *key, void *data)
{
if (key && *key)
{
AppContext *context = GetAppContext();
AppProperty *p1, *p2, *prop;
void *prev;
int d;
for (p1=context->proplist, p2=NULL; p1; p1=p1->next)
{
d = strcmp(key,p1->key);
if (d < 0) break;
if (d==0)
{
prev = p1->data;
p1->data = data;
return prev; /* previous value */
}
p2 = p1;
}
/*
* If we reach here, a property with the given key does not exist, so
* let's create a new one and link it into the list.
*/
if (AppContext_IsLocked(context))
{
TRACE("SetAppProperty: ** property list is locked **\n");
}
else
{
AppContext_Lock(context);
if ((prop = new_AppProperty(key,data)) != NULL)
{
if (p2 == NULL)
context->proplist = prop;
else
p2->next = prop;
prop->next = p1;
}
AppContext_Unlock(context);
}
}
return NULL; /* no previous value */
}
/* ----------------------------------------------------------------------
* GetAppProperty -- Retrieves data value that was set with SetAppProperty.
*
* Parameters:
* key: key identifying the property
*
* Return value:
* Value that was set with SetAppProperty or NULL if no property with
* that key exists.
*
* Created:
* 06-08-93 Schuler
* Modified:
* 00-00-00 YourName What changes did you make?
*
* ---------------------------------------------------------------------- */
void * LIBCALL Nlm_GetAppProperty (const char *key)
{
if (key && *key)
{
AppContext *context = GetAppContext();
AppProperty *prop;
for (prop=context->proplist; prop; prop=prop->next)
{
if (strcmp(prop->key,key) ==0)
return prop->data;
}
}
return NULL;
}
/* ----------------------------------------------------------------------
* RemoveAppProperty -- Removes a propery from the application context's
* property list (if it exists) and returns the data value that was
* set with SetAppParam().
*
* Parameters:
* key: key identifying the property
*
* Return value:
* Value that was set with SetAppProperty or NULL if no property with
* that key exists.
*
* Notes:
* It is the responsibiliy of the caller to free whatever resources
* the property's data (return value) may happen to point to.
*
* Created:
* 06-08-93 Schuler
* Modified:
* 00-00-00 YourName What changes did you make?
*
* ---------------------------------------------------------------------- */
void * LIBCALL Nlm_RemoveAppProperty (const char *key)
{
if (key && *key)
{
AppContext *context = GetAppContext();
if (AppContext_IsLocked(context))
{
TRACE("RemoveAppProperty: ** property list is locked **\n");
}
else
{
AppProperty *p1, *p2;
int d;
AppContext_Lock(context);
for (p1=context->proplist, p2=NULL; p1; p1=p1->next)
{
d = strcmp(key,p1->key);
if (d < 0) break;
if (d==0)
{
void *data = p1->data;
if (p2 == NULL)
context->proplist = p1->next;
else
p2->next = p1->next;
delete_AppProperty(p1);
AppContext_Unlock(context);
return data; /* success */
}
p2 = p1;
}
AppContext_Unlock(context);
}
}
return NULL; /* failure */
}
/* ----------------------------------------------------------------------
* EnumAppProperties -- Enumerates all application properties, calling
* a caller-supplied callback function with the key and data for
* each one.
*
* Parameters:
* Pointer to the enumeration callback procedure.
*
* Return value:
* Number of properties enumerated.
*
* Callback function:
*
* int LIBCALLBACK MyEmumProc (const char *key, void *value)
* {
* //--- insert your code here ---
*
* // for example:
* if (strcmp(key,"MyBigBuffer") ==0)
* {
* SetAppProperty(key,NULL);
* MemFree(data)
* return FALSE; // FALSE to stop enumeration at this point
* }
* return TRUE; // TRUE to continue the enumeration.
* }
*
* Notes:
* It is OK to call SetAppProperty() from within the callback function,
* but _only_ to change the value of an existing property. Any attempt
* to alter the property list, either by calling SetAppProperty() with
* a new key or calling RemoveAppProperty() will fail while an enumera-
* tion is in progress.
*
* Created:
* 06-09-93 Schuler
* Modified:
* 00-00-00 YourName What changes did you make?
*
* ---------------------------------------------------------------------- */
int LIBCALL Nlm_EnumAppProperties (Nlm_AppPropEnumProc proc)
{
int count = 0;
if (proc != NULL)
{
AppContext *context = GetAppContext();
AppProperty *prop;
if (context->enums==0)
AppContext_Lock(context);
context->enums++;
for (prop=context->proplist; prop; prop=prop->next)
{
count ++;
if ( ! (*proc)(prop->key,prop->data) )
break;
}
context->enums--;
if (context->enums==0)
AppContext_Unlock(context);
}
return count;
}
/* ----------------------------------------------------------------------
* GetAppProcessID [Schuler, 06-04-93]
*
* Returns an identifier for the current application instance.
*
* Notes:
* On the Macintosh, the process ID is a 64-bit value, which is being
* condensed down to 32-bits here by XORing the high and low halves
* of the value. I can't guarantee it will be unique (although it
* seems to be in practice), but this code is not being dynamically
* linked on the Mac, so it doesn't matter.
*
* MODIFICATIONS
* 04-10-93 Schuler Added Macintosh version.
* 12-16-93 Schuler Added Borland version contributed by M.Copperwhite
* ---------------------------------------------------------------------- */
#define USE_GETPID
/* (insert other platform-specific versions here as necessary and #undef USE_GETPID) */
/* ----- Macintosh Version ----- */
#ifdef OS_MAC
#include <Processes.h>
#include <GestaltEqu.h>
long LIBCALL Nlm_GetAppProcessID (void)
{
long gval;
ProcessSerialNumber psn; /* a 64-bit value*/
if (Gestalt (gestaltSystemVersion, &gval) == noErr && (short) gval >= 7 * 256) {
GetCurrentProcess(&psn);
return (psn.highLongOfPSN ^ psn.lowLongOfPSN); /* merge to 32-bits */
} else {
return 1;
}
}
#undef USE_GETPID
#endif
/* ----- NCBIDLL mod Borland DLL version - call Windows API to get PSP ----- */
#ifdef _WINDLL
#ifdef COMP_BOR
long LIBCALL Nlm_GetAppProcessID (void)
{
return GetCurrentPDB();
}
#undef USE_GETPID
#endif
#endif
/* ----- Generic Version ----- */
#ifdef USE_GETPID
#if defined(COMP_MSC) || defined(COMP_BOR)
#include <process.h>
#ifdef COMP_CWI
#define getpid _getpid
#endif
#endif
long LIBCALL Nlm_GetAppProcessID (void)
{
#ifdef COMP_CWI
return 0;
#else
return getpid();
#endif
}
#endif